package tse

import (
	"gitee.com/amoyx/cloud-provider/pkg/cloud/tencent/models"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common"
	"github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common/profile"
	tregion "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/region/v20220627"
	tdmq "github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/tdmq/v20200217"
)

type RabbitMQGreeter interface {
	RabbitMQ(region string) RabbitMQInterface
}

type RabbitMQInterface interface {
	CreateInstance(args models.RabbitMQRequest) (result models.CreateResponseParams, err error)
	DeleteInstance(id string) (err error)
	Get(id string) (result models.RabbitMQItem, err error)
	ListByName(name string) (list []models.RabbitMQItem, err error)
	ListAll() (list []models.RabbitMQItem, err error)
	RegionList() (list []models.RegionResponse, err error)
	UserListOfRMQ(id string) (list []models.RabbitMQUser, err error)
	DeleteUserOfRMQ(id string, user string) (err error)
	CreateUserOfRMQ(id string, user string, passwd string, dest string) (err error)
	ModifyUserPasswdOfRMQ(id string, user string, passwd string) (err error)
	ZoneList() (list []models.ZoneResponse, err error)
}

type rabbitmq struct {
	tse    *TSE
	region string
	client *tdmq.Client
}

func newRabbitMQ(tse *TSE, region string) RabbitMQInterface {
	v := &rabbitmq{
		tse:    tse,
		region: region,
	}
	cpf := profile.NewClientProfile()
	cpf.HttpProfile.Endpoint = string(TDMQEndPoint)
	client, _ := tdmq.NewClient(v.tse.Credential(), v.region, cpf)
	v.client = client
	return v
}

func (r *rabbitmq) CreateInstance(args models.RabbitMQRequest) (result models.CreateResponseParams, err error) {
	request := tdmq.NewCreateRabbitMQVipInstanceRequest()
	request.VpcId = common.StringPtr(args.VpcId)
	request.SubnetId = common.StringPtr(args.SubnetId)
	request.ZoneIds = common.Int64Ptrs(args.ZoneIds)
	request.ClusterName = common.StringPtr(args.ClusterName)
	if r.verifyNodeSpec(args.NodeSpec) {
		request.NodeSpec = common.StringPtr(args.NodeSpec)
	}
	if r.verifyNodeNumber(args.NodeNum) {
		request.NodeNum = common.Int64Ptr(args.NodeNum)
	}
	if r.verifyDiskSize(args.StorageSize) {
		request.StorageSize = common.Int64Ptr(args.StorageSize)
	}
	request.AutoRenewFlag = common.BoolPtr(true)
	request.TimeSpan = common.Int64Ptr(1)
	response, err := r.client.CreateRabbitMQVipInstance(request)
	if err != nil {
		return
	}
	res := response.Response
	result.RequestId = *res.RequestId
	result.InstanceSet = append(result.InstanceSet, *res.InstanceId)
	return
}

func (r *rabbitmq) DeleteInstance(id string) (err error) {
	request := tdmq.NewDeleteRabbitMQVipInstanceRequest()
	request.InstanceId = common.StringPtr(id)
	_, err = r.client.DeleteRabbitMQVipInstance(request)
	return
}

func (r *rabbitmq) Get(id string) (result models.RabbitMQItem, err error) {
	list, err := r.query(map[string]string{"InstanceId": id})
	if len(list) > 0 {
		result = list[0]
	}
	return
}

func (r *rabbitmq) ListByName(name string) (list []models.RabbitMQItem, err error) {
	return r.query(map[string]string{"InstanceName": name})
}

func (r *rabbitmq) ListAll() (list []models.RabbitMQItem, err error) {
	return r.query(map[string]string{})
}

func (r *rabbitmq) verifyNodeNumber(n int64) bool {
	if n >= 1 && n <= 7 && n%2 != 0 {
		return true
	}
	return false
}

func (r *rabbitmq) verifyNodeSpec(spec string) bool {
	list := []string{"rabbit-vip-basic-1", "rabbit-vip-basic-2", "rabbit-vip-basic-3", "rabbit-vip-basic-4", "rabbit-vip-basic-5"}
	for _, val := range list {
		if val == spec {
			return true
		}
	}
	return false
}

func (r *rabbitmq) verifyDiskSize(size int64) bool {
	if size >= 200 && size <= 1000 {
		return true
	}
	return false
}

func (r *rabbitmq) query(args map[string]string) (list []models.RabbitMQItem, err error) {
	request := tdmq.NewDescribeRabbitMQVipInstancesRequest()
	var filters []*tdmq.Filter
	for key, val := range args {
		filters = append(filters,
			&tdmq.Filter{
				Name:   common.StringPtr(key),
				Values: common.StringPtrs([]string{val}),
			})
	}
	request.Filters = filters
	request.Limit = common.Uint64Ptr(20)
	request.Offset = common.Uint64Ptr(0)
	response, err := r.client.DescribeRabbitMQVipInstances(request)
	if err != nil {
		return
	}
	for _, row := range response.Response.Instances {
		list = append(list, models.RabbitMQItem{
			InstanceId:      *row.InstanceId,
			InstanceName:    *row.InstanceName,
			InstanceVersion: *row.InstanceVersion,
			Status:          *row.Status,
			NodeCount:       *row.NodeCount,
			ConfigDisplay:   *row.ConfigDisplay,
			MaxTps:          *row.MaxTps,
			MaxBandWidth:    *row.MaxBandWidth,
			MaxStorage:      *row.MaxStorage,
			ExpireTime:      *row.ExpireTime,
			AutoRenewFlag:   *row.AutoRenewFlag,
			PayMode:         *row.PayMode,
			Remark:          *row.Remark,
			SpecName:        *row.SpecName,
			ClusterStatus:   *row.ClusterStatus,
		})
	}
	return
}

func (r *rabbitmq) UserListOfRMQ(id string) (list []models.RabbitMQUser, err error) {
	request := tdmq.NewDescribeRabbitMQUserRequest()
	request.InstanceId = common.StringPtr(id)
	request.Offset = common.Int64Ptr(0)
	request.Limit = common.Int64Ptr(100)
	response, err := r.client.DescribeRabbitMQUser(request)
	if err != nil {
		return
	}
	for _, row := range response.Response.RabbitMQUserList {
		list = append(list, models.RabbitMQUser{
			InstanceId:  *row.InstanceId,
			User:        *row.User,
			Password:    *row.Password,
			Description: *row.Description,
			CreateTime:  *row.CreateTime,
			ModifyTime:  *row.ModifyTime,
			Type:        *row.Type,
		})
	}
	return
}

func (r *rabbitmq) DeleteUserOfRMQ(id string, user string) (err error) {
	request := tdmq.NewDeleteRabbitMQUserRequest()
	request.InstanceId = common.StringPtr(id)
	request.User = common.StringPtr(user)
	_, err = r.client.DeleteRabbitMQUser(request)
	return
}

func (r *rabbitmq) CreateUserOfRMQ(id string, user string, passwd string, dest string) (err error) {
	request := tdmq.NewCreateRabbitMQUserRequest()
	request.InstanceId = common.StringPtr(id)
	request.User = common.StringPtr(user)
	request.Password = common.StringPtr(passwd)
	request.Description = common.StringPtr(dest)
	request.MaxConnections = common.Int64Ptr(1000)
	request.MaxChannels = common.Int64Ptr(2000)
	_, err = r.client.CreateRabbitMQUser(request)
	return
}

func (r *rabbitmq) ModifyUserPasswdOfRMQ(id string, user string, passwd string) (err error) {
	request := tdmq.NewModifyRabbitMQUserRequest()
	request.InstanceId = common.StringPtr(id)
	request.User = common.StringPtr(user)
	request.Password = common.StringPtr(passwd)
	_, err = r.client.ModifyRabbitMQUser(request)
	return
}

func (r *rabbitmq) RegionList() (list []models.RegionResponse, err error) {
	cpf := profile.NewClientProfile()
	cpf.HttpProfile.Endpoint = "region.tencentcloudapi.com"
	client, _ := tregion.NewClient(r.tse.Credential(), r.region, cpf)
	request := tregion.NewDescribeRegionsRequest()
	request.Product = common.StringPtr("tdmq")
	response, err := client.DescribeRegions(request)
	if err != nil {
		return
	}
	for _, val := range response.Response.RegionSet {
		list = append(list, models.RegionResponse{
			Region:      *val.Region,
			RegionName:  *val.RegionName,
			RegionState: *val.RegionState,
		})
	}
	return
}

func (r *rabbitmq) ZoneList() (list []models.ZoneResponse, err error) {
	cpf := profile.NewClientProfile()
	cpf.HttpProfile.Endpoint = "region.tencentcloudapi.com"
	client, _ := tregion.NewClient(r.tse.Credential(), r.region, cpf)
	request := tregion.NewDescribeZonesRequest()
	request.Product = common.StringPtr("tdmq")
	response, err := client.DescribeZones(request)
	if err != nil {
		return
	}
	for _, val := range response.Response.ZoneSet {
		list = append(list, models.ZoneResponse{
			Zone:      *val.Zone,
			ZoneId:    *val.ZoneId,
			ZoneName:  *val.ZoneName,
			ZoneState: *val.ZoneState,
		})
	}
	return
}
